/**
 *
 *      ___                       ___
 *     /\  \          ___        /\  \
 *    /::\  \        /\  \      /::\  \
 *   /:/\:\  \       \:\  \    /:/\ \  \
 *  /:/  \:\  \      /::\__\  _\:\~\ \  \
 * /:/__/ \:\__\  __/:/\/__/ /\ \:\ \ \__\
 * \:\  \  \/__/ /\/:/  /    \:\ \:\ \/__/
 *  \:\  \       \::/__/      \:\ \:\__\
 *   \:\  \       \:\__\       \:\/:/  /
 *    \:\__\       \/__/        \::/  /
 *     \/__/                     \/__/
 *
 * CIS - Clang Indexing Service is a Project Manager & Source code indexing service
 * created so as to simplify the indexing of C/C++ based source code which use
 * standardized build mechanisms.
 *
 **/

#include "../includes/indexserverconn.hxx"
#include "../includes/requestprocessor.hxx"

#include <Poco/Logger.h>
#include <Poco/LogStream.h>

using namespace Poco::Net;
using namespace cis;

namespace {
Poco::Logger& logger = Poco::Logger::get("IndexServerConn");
Poco::LogStream logstream(logger);
}

void IndexServerConn::run()
{
#define SIZE 1000
    std::string msg, lastRequest;
    char BUFF[SIZE] = {0};
    bool completeRequest = false;
    try {
        while (true) {
            size_t sz = this->socket().receiveBytes(BUFF, SIZE);
            msg.append(BUFF, sz);
            int msgSize = isCompleteRequest(msg);
            while (msgSize > 0) {
                lastRequest = msg.substr(0, msgSize);
                msg.erase(0, msgSize);
                completeRequest = true;
                std::string ret = serveRequest(lastRequest);
                socketStream << ret << std::flush;
                msgSize = isCompleteRequest(msg);
            }
        }

    } catch (Poco::Exception& e) {
        /* close the connection and return the error packet */
        logstream.error() << "Exception caught while serving the client [" << e.message() << "]" << std::endl;
        socket().close();
    } catch (std::exception& e) {
        /* close the connection and return the error packet */
        logstream.error() << "Exception caught while serving the client [" << e.what() << "]" << std::endl;
        socket().close();
    }
#undef SIZE
}

std::string IndexServerConn::serveRequest(const std::string& request) const
{
    RequestProcessor jrp;
    return jrp.execute(request);
}

long IndexServerConn::isCompleteRequest(const std::string& str) const
{

    const char *curr = str.c_str();
    int len = str.length();
    const char *buff = curr;

    if (len == 0) return 0;
    size_t braces = 0;
    while ((curr - buff < len) && (*curr == ' ' || *curr == '\t' || *curr == '\n' || *curr == '\r')) curr++; // skip initial spaces

    if (curr - buff >= len) return -1;

    if (*curr != '{')
        throw std::runtime_error("cannot validate the message properly - it doesn't begin with '{'.");
    else braces++;
    curr++;
    while (braces != 0 && (curr - buff < len)) {
        switch (*curr) {
        case '{':
            braces++;
            break;
        case '}':
            braces--;
            break;
        }
        if (braces != 0)
            curr++;
        else
            break;
    }
    if (braces == 0) return curr - buff + 1;
    return -1;
}

IndexServerConn::~IndexServerConn()
{
}

